
window.MVC = function(){};

MVC.Model = Class({
	Implements: Events,
	document:{},
	options: {
		skipBinds: false
	},
	ready: false,
	sourceView: '',
	initialize: function(url) {
		if (!url) return;
		this.options.url = url;
	},
	fromResponse: function(rq) {
		if (!rq.response.text) throw('No data in response: '+rq.options.url);
		this.document = this.stringToXML(rq.response.text);
		// Bro.log('RESPONSE TEXT: '+rq.response.text);
		if ("data" in this.document.firstChild) {
			var d = /href=["'](.*)["']/.exec(rq.response.text);
			var data = '';
			if (d) {
//				var rg = new RegExp("amp;", 'ig');
//				/rg.global = true;
				this.sourceView = (d[1]+'').replace(/&amp;/ig, '&');
			}
			// Bro.log('SOURCEVIEW: '+this.sourceView);
			 
		}
		this.fireEvent('complete');
	},
	reload: function(data, params, onDone) {
		// Bro.log('model.reload');
		if (!params) params = {};
		params.async = false;
		if (!params.url) params.url = this.options.url;
		if (!params.url) throw "no request url specfied!";
		var dt = new Date();
		if (params.url.match(/\?/)) params.url += '&'+dt.getTime();
		else params.url += '?'+dt.getTime();
		window.ppp = params;
		var rq = new Request(params);
		if (!data) data = null;
		
		rq.caller = this;
		rq.addEvent('complete', function(){
			this.caller.fromResponse(rq);
			if(onDone) onDone.call();
		});
		rq.send(data);
	}, 
	stringToXML: function(xmlData) {
		if (!xmlData) throw "unable to create xml: no input text specified!";
		if (window.ActiveXObject) {
			// for IE
			xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async="false";
			xmlDoc.loadXML(xmlData);
			return xmlDoc;
		} else if (document.implementation && document.implementation.createDocument) {
			// for Mozila
			parser=new DOMParser();
			xmlDoc=parser.parseFromString(xmlData,"text/xml");
			xmlDoc.serialize = this.__serialize;
			return xmlDoc;
		}
	},
	__serialize: function(elem) {
		if(typeof(elem) == 'string') return elem;
		if (window.ActiveXObject) {
			return elem.xml;
		} else {
			return (new XMLSerializer()).serializeToString(elem);
		}
	},
	transform: function(xsl) {
		var oProcessor = new XSLTProcessor();
		oProcessor.importStylesheet(xsl);
	    var oResultDom = oProcessor.transformToDocument(this.document);
	    oResultDom.serialize = this.__serialize;
	    return oResultDom; 
	}
});

MVC.View = Class({
	Extends: MVC.Model,
	Implements: Options,
	document: {},
	handlers: {},
	hSrc: false,
	initialize: function(url, options, document) {
		// Bro.log('View.init');
		if (!options) options = {};
		options.url = url;
		this.setOptions(options);
		if (document) this.document = document;
		this.parent(this.options.url);
	},
	ajaxRender: function(url, target) {
		var model = new MVC.Model(url);
		model.addEvent('load', function() {
			this.render(model, target);
		});
		return model;
	},
	call: function(state, data, target) {
		// Bro.log('View.call');
		var app = 'gui';
		if (state.match(/\./)) {
			var st = state.split('.');
			app = st[0];
			state = st[1];
		}
			
		// Bro.log('View.call');
		var url1 = 'index.php?query_id='+Xendri.nextQueryID()+'&query_type=XML&application='+app+'&state='+state;
		var url2 = 'index.php?query_id='+Xendri.nextQueryID()+'&query_type=XSLT&application='+app+'&state='+state;
		var model = new MVC.Model(url1);
		this.options.model = model;
		var t = this;
		data = (new Hash(data)).toQueryString(); 
		this.reload(data, {url:url2}, function() {
			t.render(model, target);
		});
	},
	__reload : function(data, params, onDone) {
		// Bro.log('View.__reload');
		if (!params) params = {};
		params.async = false;
		if (!params.url) params.url = this.options.url;
		if (!params.url) throw "no request url specfied!";
		var dt = new Date();
		if (params.url.match(/\?/)) params.url += '&'+dt.getTime();
		else params.url += '?'+dt.getTime();
		window.ppp = params;
		var rq = new Request(params);
		if (!data) data = '';
		
		rq.caller = this;
		rq.addEvent('complete', function(){
			this.caller.fromResponse(rq);
			if(onDone) onDone.call();
		});
		rq.send(data);
	}, 
	reload: function(data, params, onDone) {
		// Bro.log('View.reload');
		if (!params) var params = {};
		params.url = (this.options.model.sourceView || this.options.url || params.url);
		if (this.options.model) {
			var t = this;
			this.options.model.reload(data, {}, function() {
				// Bro.log('Model.onload');
				t.__reload(data, params, onDone); 
			});
		} else {
			this.__reload(data, params, onDone);
		}
	},
	render: function(model, target) {
		// Bro.log('View.render');
		// TODO: xslt processing
		if(!model) model = this.options.model;
		target = (this.options.target || target || 'data');
		target = $(target);
		if (window.ActiveXObject) { 
			var result = model.document.transformNode(this.document);
		} else {
			var result = model.transform(this.document);
		}
		
		
		var res = this.__serialize(result);
		$(target).empty();
		$(target).innerHTML = res;
		document.fireEvent('change');
		if ($(target).getElement('handlers')) {
			this.hSrc = $(target).getElement('handlers').getAttribute('src');
		}
		this.bindHandlers();
		this.fireEvent('render');
	},
	renderDefaults: function() {
		// Bro.log('View.renderDefaults');
		var m = this;
		this.options.model.reload(null,null, function() {
			// Bro.log('Model.onload');
			m.reload(null, null, function() {
				// Bro.log('View.onload');
				m.render();
			})
		});
	},
	bindHandlers: function() {
		 Bro.log('Hsrc: '+this.hSrc);
		if (this.hSrc) {
			Xendri.JSload(this.hSrc);
			return;
		} 

		if (this.options.handlers) {
			for (var el in handlers) {
				for (var evt in handlers[el]) {
					result.getElements(el).addEvent(evt, handlers[el][evt]);
				}
			}
		}
	}
});

MVC.Cascade = Class({
	Implements: Events,
	cascade: [],
	initialize: function() {
		if (arguments.length > 1) {
			this.cascade = arguments;
		} else if (arguments.length == 1) {
			this.cascade = arguments[0];
		}
	},
	run: function() {
		this.next();
	},
	next: function() {
		var act = this.cascade.shift();
		if (!act) {
			this.fireEvent('complete');
			return;
		}
		var m = this;
		act.addEvent('render', function() {
			m.next();
		});	
		act.renderDefaults();
	}
});